package com.boot.down.service.impl;

import com.boot.down.entity.RedPaper;
import com.boot.down.entity.UserRedPaper;
import com.boot.down.mapper.RedPaperMapper;
import com.boot.down.mapper.UserRedPaperMapper;
import com.boot.down.service.RedisRedPaperService;
import com.boot.down.service.UserRedPaperService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import redis.clients.jedis.Jedis;

import java.math.BigDecimal;
import java.util.Date;

/**
 *实现用户抢红包功能
 *
 */
@Service
public class UserRedPaperServiceImpl implements UserRedPaperService {

    @Autowired
    private UserRedPaperMapper userRedPaperMapper = null;

    @Autowired
    private RedPaperMapper redPaperMapper = null;

    //失败
    private static final int FAILED = 0;


    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    public int addUserRedPaper(Long redId, Long userId) {

        //获取红包信息
        RedPaper redPaper = redPaperMapper.getRedPaper(redId);
        //利用数据库的悲观锁
        //RedPaper redPaper = redPaperMapper.getRedPaperForUpdate(redId);
        //判断红包剩余数量
        if(redPaper.getSmallSupCount() > 0){
            //先减数量
            //redPaperMapper.decreaseRedPaper(redId);
            int update = redPaperMapper.decreaseRedPaperHappyLock(redId, redPaper.getVersion());
            //如果没有数据更新， 说明已经被其他线程修改，及抢红包失败
            if(update == 0){
                return FAILED;
            }
            //生成抢红包信息
            return insertUserRedPaper(redId, userId, redPaper);
        }
        return FAILED;
    }

    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    public int addUserRedPaperHappyLock(Long redId, Long userId) {

        long start  = System.currentTimeMillis();
        //运用循环条件进行重入机制
        while (true){
            long end = System.currentTimeMillis();
            if(end - start > 100){
                return FAILED;
            }

            RedPaper redPaper = redPaperMapper.getRedPaper(redId);

            if(redPaper.getSmallSupCount() > 0){
                int update = redPaperMapper.decreaseRedPaperHappyLock(redId, redPaper.getVersion());
                //如果没有数据更新， 说明已经被其他线程修改，及抢红包失败
                if(update == 0){
                    continue;
                }
                //生成抢红包信息
                return insertUserRedPaper(redId, userId, redPaper);
            }else{
                //没有库存
                return FAILED;
            }

        }
    }

    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    public int insertUserRedPaper(Long redId, Long userId, RedPaper redPaper) {
        UserRedPaper userRedPaper = new UserRedPaper();
        userRedPaper.setRedId(redId);
        userRedPaper.setUserId(userId);
        userRedPaper.setCreateTime(new Date());
        userRedPaper.setAmount(redPaper.getSmallPrice());
        userRedPaper.setRemark("抢红包"+ redId);
        int result = userRedPaperMapper.insertRedPaper(userRedPaper);
        return result;
    }

    @Autowired
    private RedisTemplate redisTemplate = null;

    @Autowired
    private RedisRedPaperService redisRedPaperService = null;
    //lua脚本
    String script = "local listKey = 'red_paper_list_'..KEYS[1] \n" +
            "local redPaper = 'red_paper_'..KEYS[1] \n" +
            "local smallSupCount = tonumber(redis.call('hget', redPaper, 'smallSupCount')) \n" +
            "if smallSupCount <= 0 then return 0 end \n" +
            "smallSupCount = smallSupCount -1 \n" +
            "redis.call('hset', redPaper, 'smallSupCount', tostring(smallSupCount)) \n" +
            "redis.call('rpush', listKey, ARGV[1]) \n" +
            "if smallSupCount == 0 then return 2 end \n" +
            "return 1 \n";
    String sha1 = null;

    @Override
    public Long grapUserRedPaperByRedis(Long redPaperId, Long userId) {

        String args = userId + "-" + System.currentTimeMillis();
        Long result = null;
        //获取redis 底层进行操作
        Jedis jedis = (Jedis) redisTemplate.getConnectionFactory().getConnection().getNativeConnection();
        if(sha1 == null){
            sha1 = jedis.scriptLoad(script);
        }
        //执行脚本返回结果
        Object res = jedis.evalsha(sha1,1, redPaperId+"", args);
        result = (Long) res;
        try {
            if(result == 2){
                String smPriceStr = jedis.hget("red_paper_" + redPaperId, "smallPrice");
                //保存数据库操作
                BigDecimal smPrice = new BigDecimal(smPriceStr);
                System.err.println("thread_name = " + Thread.currentThread().getName());
                redisRedPaperService.saveUserRedPaperByRedis(redPaperId, smPrice);
            }
        }finally {
            //确保redis顺利关闭
            if(jedis != null && jedis.isConnected()){
                jedis.close();
            }
        }
        return result;
    }
}
